
package com.dog.basics.service.common.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.dog.basics.bean.dto.admin.common.AdminUserConnectPageDto;
import com.dog.basics.bean.dto.admin.common.AdminUserConnectEditDto;
import com.dog.basics.bean.dto.admin.common.AdminUserConnectPageDto;
import com.dog.basics.bean.model.common.DogConnectFlowing;
import com.dog.basics.bean.model.common.DogUserConnect;
import com.dog.basics.bean.vo.admin.common.AdminUserConnectPageVo;
import com.dog.basics.bean.model.sys.SysUser;
import com.dog.basics.bean.vo.admin.common.AdminUserConnectPageVo;
import com.dog.basics.common.annotation.RedisLock;
import com.dog.basics.common.constant.CommonConstants;
import com.dog.basics.common.util.PageParam;
import com.dog.basics.common.util.OrderCodeFactory;
import com.dog.basics.common.util.SpringContextUtils;
import com.dog.basics.dao.common.DogConnectFlowingMapper;
import com.dog.basics.dao.common.DogUserConnectMapper;
import com.dog.basics.dao.sys.SysUserMapper;
import com.dog.basics.security.util.SecurityUtils;
import com.dog.basics.service.common.DogUserConnectService;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

/**
 * 用户账户信息
 *
 * @author guo
 * @date 2021-06-19 12:30:55
 */
@Service
@Log4j2
@AllArgsConstructor
public class DogUserConnectServiceImpl extends ServiceImpl<DogUserConnectMapper, DogUserConnect> implements DogUserConnectService {
    private final DogConnectFlowingMapper flowingMapper;
    private final SysUserMapper userMapper;
    /**
     * @功能描述: 操作账户金额
     * @author He
     * @date 2021/6/19
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @RedisLock(lockName = "USERCONNECT", key = "'EDIT:'+#userId", expire = 20000)
    public Boolean addUserConnect(Long userId, BigDecimal money, DogConnectFlowing flowing) {
        // 判断是否操作金额大于0
        if (NumberUtil.equals(money, BigDecimal.ZERO)) {
            // 操作金额为等于0
            log.error("用户:{},操作金额:{},以成功结束", userId, money);
            return Boolean.TRUE;
        }
        // 查询账户余额
        DogUserConnect userConnect = getUserInfo(userId);
        // 判断是 加|减 【如果是扣除余额/判断是否账户余额充足】
        if (NumberUtil.isGreater(BigDecimal.ZERO, money)) {
            boolean greaterOrEqual = NumberUtil.isGreaterOrEqual(userConnect.getMoney(), money);
            Validator.validateTrue(greaterOrEqual, "user.connerct.money.Insufficient");
        }
        // 判断版本号是否大于 999999999
        Integer operationVersion = userConnect.getVersion() < CommonConstants.versionMax ? userConnect.getVersion() : Integer.valueOf(1);
        // 执行 操作账户余额信息
        Integer editUserConnect = this.baseMapper.editUserConnect(userId, money, userConnect.getVersion(), operationVersion);
        // 判断操作账户是否成功或失败
        Validator.validateTrue(SqlHelper.retBool(editUserConnect), "common.operation.failed");
        // 判断是否有流水需要添加
        if (ObjectUtil.isNotNull(flowing)) {
            // 补充操作前余额/操作后余额
            flowing.setFlowBeforeOperationMoney(userConnect.getMoney());
            flowing.setFlowAfterOperationMoney(NumberUtil.add(userConnect.getMoney(), money));
            // 补充添加时间与人员
            if (ObjectUtil.isNull(flowing.getCreateBy())) {
                flowing.setCreateBy(userId);
            }
            flowing.setCreateTime(DateUtil.currentSeconds());
            // 执行添加
            Validator.validateTrue(SqlHelper.retBool(flowingMapper.insert(flowing)), "common.operation.failed");
        }
        return Boolean.TRUE;
    }

    /**
     * @功能描述: 判断账户余额是否大于传入余额
     * @author He
     * @date 2021/6/19
     */
    @Override
    @Transactional
    public Boolean getIsUsetConnect(Long userId, BigDecimal money) {
        // 查询账户余额
        DogUserConnect userConnect = getUserInfo(userId);
        // 判断是否大于或等于
        return NumberUtil.isGreaterOrEqual(userConnect.getMoney(), money);
    }

    /**
     * @功能描述: 获取用户余额
     * @author He
     * @date 2021/6/30
     */
    @Override
    public BigDecimal getUserMoney(Long userId) {
        return getUserInfo(userId).getMoney();
    }

    /**
     * 账户余额分页
     *
     * @param param
     * @param dto
     * @return guonh 2021年7月23日
     */
    @Override
    public IPage<AdminUserConnectPageVo> getAdminUserConnectPage(PageParam param, AdminUserConnectPageDto dto) {
        // 判断查询是否代理商还是场地
        if (Validator.equal(dto.getUserType(), 0)) {
            dto.setUserTypeCode(CommonConstants.ROLE_AGENT_CODE);
        } else {
            dto.setUserTypeCode(CommonConstants.ROLE_FIELD_CODE);
        }
        // 分页查询数据信息 - 数据信息转换返回
        this.baseMapper.getAdminUserConnectPage(param, dto);
        return param;
    }

    /**
     * 扣除账户金额
     *
     * @param dto
     * @return guonh 2021年7月23日
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean putAdminUserConnectEdit(AdminUserConnectEditDto dto) {
        // 判断扣除金额是否大于0
        boolean greater = NumberUtil.isGreater(dto.getMoney(), BigDecimal.ZERO);
        Validator.validateTrue(greater, "connect.user.money.min");
        // 查询账户是否存在
        Boolean isUsetConnect = getIsUsetConnect(dto.getUserId(), dto.getMoney());
        Validator.validateTrue(isUsetConnect, "connect.user.money.insufficient");
        // 账户信息执行封装实体 - 增添流水
        DogConnectFlowing agentFlowing = new DogConnectFlowing();
        agentFlowing.setUserId(dto.getUserId());
        agentFlowing.setFlowSerialNo(OrderCodeFactory.getWaterCode(agentFlowing.getUserId()));
        agentFlowing.setFlowMoney(dto.getMoney().negate());
        agentFlowing.setFlowType(0);
        agentFlowing.setFromType(3);
        agentFlowing.setType(1);
        agentFlowing.setObjId(CommonConstants.DEFAULT_VAL_LONG);
        agentFlowing.setFlowExplain("Management deduction");
        agentFlowing.setCreateBy(SecurityUtils.getSysUser().getUserId());
        // 执行账户信息操作
        addUserConnect(agentFlowing.getUserId(), agentFlowing.getFlowMoney(), agentFlowing);
        return Boolean.TRUE;
    }


    /**
     * @功能描述: 获取用户金额信息【判断是否有-无则添加】
     * @author He
     * @date 2021/6/30
     */
    private DogUserConnect getUserInfo(Long userId) {
        // 查询账户余额
        DogUserConnect userConnect = this.getById(userId);
        // 判断账户是否存在 [不存在则添加一个]
        if (ObjectUtil.isNull(userConnect)) {
            // 判断数据是否存在
            SysUser user = userMapper.selectById(userId);
            Validator.validateNotNull(user, "账户不存在");
            // 处理数据信息
            userConnect = new DogUserConnect();
            userConnect.setPoint(Integer.valueOf(0));
            userConnect.setMoney(BigDecimal.ZERO);
            userConnect.setUserId(userId);
            userConnect.setVersion(0);
            userConnect.setCreateTime(DateUtil.currentSeconds());
            userConnect.setCreateBy(userId);
            Validator.validateTrue(this.save(userConnect), "账户操作失败");
        }
        return userConnect;
    }
}
